﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.IO;
using System.Reflection;
using System.ServiceModel;
using System.ServiceModel.Description;
using nwrole.lib;

namespace nwrole.service
{
    public partial class SupervisorService : ServiceBase
    {
        public static string Identifier = "nwrole.service.supervisor";
        public static string ApplicationDirectory = "nwrole";
        public static string ServiceDisplayName = "nwrole Supervisor";
        public static string ApplicationExe = "nwrole.service.exe";

        // public static int SupervisorPort = 8082;
        public static int SupervisorPort = 8084;

        private Supervisor supervisor;
        private Uri baseAddress = new Uri("net.tcp://0.0.0.0:" + SupervisorPort);
        private ServiceHost serviceHost;

        public SupervisorService ()
        {
            InitializeComponent();
        }

        protected override void OnStart (string[] args)
        {
            EventLogger.LogInformation("SupervisorService.OnStart", "SupervisorService starting");
            try
            {
                if (serviceHost != null)
                    serviceHost.Close();
                if (supervisor != null)
                    supervisor.OnStop();

                supervisor = new Supervisor();
                serviceHost = new ServiceHost(supervisor, baseAddress);
                NetTcpBinding binding = new NetTcpBinding();
                binding.ReaderQuotas = System.Xml.XmlDictionaryReaderQuotas.Max;
                binding.MaxReceivedMessageSize = 2147483647;
                serviceHost.Credentials.WindowsAuthentication.AllowAnonymousLogons = true;
                serviceHost.Credentials.UserNameAuthentication.UserNamePasswordValidationMode = System.ServiceModel.Security.UserNamePasswordValidationMode.Windows;
                serviceHost.AddServiceEndpoint(typeof(ISupervisor), binding, "Supervisor");
                serviceHost.Faulted += new EventHandler(serviceHost_Faulted);
                serviceHost.Opening += new EventHandler(serviceHost_Opening);
                serviceHost.Opened += new EventHandler(serviceHost_Opened);
                serviceHost.Open();

                supervisor.OnStart();
            }
            catch (Exception exception)
            {
                EventLogger.LogException("SupervisorService.OnStart", exception);
            }
            EventLogger.LogInformation("SupervisorService.OnStart", "SupervisorService started");
        }

        void serviceHost_Opened(object sender, EventArgs e)
        {
            EventLogger.LogInformation("SupervisorService.OnStart", "SupervisorService serviceHost Opened");
        }

        void serviceHost_Opening(object sender, EventArgs e)
        {
            EventLogger.LogInformation("SupervisorService.OnStart", "SupervisorService serviceHost Opening");
        }

        void serviceHost_Faulted(object sender, EventArgs e)
        {
            StringBuilder sb = new StringBuilder();
            if (sender != null)
            {
                sb.Append(sender.ToString());
            }
            if (e != null)
            {
                sb.Append(e.ToString());
            }

            EventLogger.LogInformation("SupervisorService.OnStart", "SupervisorService serviceHost Faulted: " + sb.ToString());
        }

        protected override void OnStop ()
        {
            EventLogger.LogInformation("SupervisorService.OnStop", "SupervisorService stopping");

            if (serviceHost != null)
            {
                supervisor.OnStop();
                serviceHost.Close();
                serviceHost = null;
                supervisor = null;
            }

            EventLogger.LogInformation("SupervisorService.OnStop", "SupervisorService stopped");
        }

        #region Service management
        public static bool IsInstalled
        {
            get
            {
                ServiceController ctrl = new ServiceController(Identifier);
                try
                {
                    ServiceControllerStatus status = ctrl.Status;
                    return true;
                }
                catch (Exception) { return false; }
                finally { ctrl.Dispose(); }
            }
        }

        public static bool IsRunning
        {
            get
            {
                if (!IsInstalled)
                    return false;
                ServiceController ctrl = new ServiceController(Identifier);
                try { return ctrl.Status == ServiceControllerStatus.Running; }
                finally { if (ctrl != null) ctrl.Dispose(); }
            }
        }

        public static void StartSupervisor ()
        {
            if (!IsInstalled)
                return;
            ServiceController ctrl = new ServiceController(Identifier);
            try
            {
                ctrl.Start();
                ctrl.WaitForStatus(ServiceControllerStatus.Running);
            }
            finally { if (ctrl != null) ctrl.Dispose(); }
        }

        public static void StopSupervisor ()
        {
            if (!IsRunning)
                return;
            ServiceController ctrl = new ServiceController(Identifier);
            try
            {
                ctrl.Stop();
                ctrl.WaitForStatus(ServiceControllerStatus.Stopped);
            }
            finally { if (ctrl != null) ctrl.Dispose(); }
        }

        public static void InstallSupervisor (string username, string password)
        {
            string rootFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), ApplicationDirectory);

            UpdateSupervisor();

            ServiceUtil.InstallService(Path.Combine(rootFolder, ApplicationExe) + " supervisor", SupervisorService.Identifier, ServiceDisplayName, username, password);

            EventLogger.LogInformation("SupervisorService installed");
        }

        public static void UpdateSupervisor()
        {
            string rootFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), ApplicationDirectory);

            if (!Directory.Exists(rootFolder))
                Directory.CreateDirectory(rootFolder);

            // Metod 1
            /*foreach (AssemblyName assemblyName in Assembly.GetExecutingAssembly().GetReferencedAssemblies())
            {
                Assembly assembly = Assembly.Load(assemblyName);
                if (!assembly.GlobalAssemblyCache)
                {
                    string name = Path.GetFileName(assembly.Location);
                    File.Copy(assembly.Location, Path.Combine(rootFolder, name), true);
                }
            }*/

            // Metod 2
            // copy the needed dll's
            foreach (string name in new string[] { "nwrole.lib.dll", "nwrole.service.exe", "ICSharpCode.SharpZipLib.dll" })
            {
                string source = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), name);
                File.Copy(source, Path.Combine(rootFolder, name), true);
            }
        }

        public static void UninstallSupervisor ()
        {
            string rootFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), ApplicationDirectory);

            ServiceUtil.UninstallService(SupervisorService.Identifier);

            if (Directory.Exists(rootFolder))
                Directory.Delete(rootFolder, true);

            EventLogger.LogInformation("SupervisorService uninstalled");
        }
        #endregion
    }
}
